import Modify from 'ol/interaction/Modify'
import { always, never, platformModifierKeyOnly, primaryAction } from 'ol/events/condition'
import { toLonLat } from 'ol/proj'
import LngLat from './WLngLat'
import { calculateGraphCenter, formatRadiusToMeters } from './utils'

class WGraphEdit {
  constructor (map) {
    this.map = map
    this.source = null // 所有要素集合
    this.modify = null // 代表编辑对象
    this.events = ['done', 'modifyend'] // 支持的事件
    this.WEvents = new Map() // 存储事件
    this.initGraph()
  }
  initGraph() {
		// 取到map类已实例化的矢量图层
		if (this.map.getVectorLayer()) {
			let vector = this.map.getVectorLayer()
			this.source = vector.getSource()
		} else {
			this.source = new VectorSource({ wrapX: false })
			let vector = new VectorLayer({
				className: 'WMap-vector-layer',
				// 数据源
				source: this.source
			})
			this.map.addLayer(vector) // 添加到图层上
		}
	}
  initEdit() {
		const defaultStyle = new Modify({ source: this.source }).getOverlay().getStyleFunction()
		let _this = this
		this.modify = new Modify({
			source: this.source,
			condition: function (event) {
				return primaryAction(event) && !platformModifierKeyOnly(event)
			},
			deleteCondition: never,
			insertVertexCondition: always,
			style: function (feature) {
				let type = _this.judgeShape(feature.get('geometries')[0])
				if (type !== 'Line') {
					feature.get('features').forEach(function (modifyFeature) {
						const modifyGeometry = modifyFeature.get('modifyGeometry')
						if (modifyGeometry) {
							const point = feature.getGeometry().getCoordinates()
							let modifyPoint = modifyGeometry.point
							if (!modifyPoint) {
								// save the initial geometry and vertex position
								modifyPoint = point
								modifyGeometry.point = modifyPoint
								modifyGeometry.geometry0 = modifyGeometry.geometry
								// get anchor and minimum radius of vertices to be used
								const result = calculateGraphCenter(modifyGeometry.geometry0)
								modifyGeometry.center = result.center
								modifyGeometry.minRadius = result.minRadius
							}
							const center = modifyGeometry.center
							const minRadius = modifyGeometry.minRadius
							let dx, dy
							dx = modifyPoint[0] - center[0]
							dy = modifyPoint[1] - center[1]
							const initialRadius = Math.sqrt(dx * dx + dy * dy)
							if (initialRadius > minRadius) {
								const initialAngle = Math.atan2(dy, dx)
								dx = point[0] - center[0]
								dy = point[1] - center[1]
								const currentRadius = Math.sqrt(dx * dx + dy * dy)
								if (currentRadius > 0) {
									const currentAngle = Math.atan2(dy, dx)
									const geometry = modifyGeometry.geometry0.clone()
									geometry.scale(currentRadius / initialRadius, undefined, center)
									const typeName = modifyGeometry.geometry0.getType()
									if (typeName === 'Polygon') {
										let shapeName = _this.judgeShape(modifyGeometry.geometry0)
										if (shapeName !== 'Rectangle') {
											geometry.rotate(currentAngle - initialAngle, center)
										}
									} else if (typeName === 'Circle') {
										geometry.translate(dx, dy)
									} else if (typeName === 'Point') {
										geometry.translate(dx, dy)
									}
									modifyGeometry.geometry = geometry
								}
							}
						}
					})
				}
				return defaultStyle(feature)
			}
		})
		this.map.addGraph(this.modify)
		this.modify.on('modifystart', e => {
			let _this = this
			e.features.forEach(function (feature) {
				let shape = _this.judgeShape(feature.getGeometry())
				if (shape === 'Rectangle') {
					// 克隆图形，不能新增点
					feature.set('modifyGeometry', { geometry: feature.getGeometry().clone() }, true)
				}
			})
		})
		this.modify.on('modifyend', e => {
			let _this = this
			e.features.forEach(function (feature) {
				const modifyGeometry = feature.get('modifyGeometry')
				if (modifyGeometry) {
					feature.setGeometry(modifyGeometry.geometry)
					feature.unset('modifyGeometry', true)
				}
				let targets = _this.WEvents.get('WGraphEdit(modifyend)')
        if (targets) {
          _this.drawFeature = _this.buildFeature(feature)
				  window.dispatchEvent(targets.costomEvent)
        }
			})
		})
	}
  /**
	 * 对数据进行修改筛选，不将原生数据返回给用户
	 */
	buildFeature(e) {
		const geo = e.getGeometry()
		let data = {}
		const type = this.judgeShape(geo)
		if (type === 'Point') {
			e.lnglat = new LngLat(...toLonLat(geo.getCoordinates()))
			data = e.lnglat
		} else if (type === 'Line') {
			const points = geo.getCoordinates()
			e.lnglat = []
			for (let i = 0; i < points.length; i++) {
				e.lnglat.push(new LngLat(...toLonLat(points[i])))
			}
			data = e.lnglat
		} else if (type === 'Circle') {
			e.lnglat = new LngLat(...toLonLat(geo.getCenter()))
			data = {
				center: e.lnglat,
				radius: Number(formatRadiusToMeters(geo).toFixed(1))
			}
		} else if (type === 'Polygon') {
			const points = geo.getCoordinates().flat(1)
			e.lnglat = []
			// 左上开始 逆时针
			for (let i = 0; i < points.length; i++) {
				e.lnglat.push(new LngLat(...toLonLat(points[i])))
			}
			data = e.lnglat.slice(1)
		} else if (type === 'Rectangle') {
			const points = geo.getCoordinates().flat(1)
			e.lnglat = []
			// 左下开始 逆时针
			for (let i = 0; i < points.length; i++) {
				e.lnglat.push(new LngLat(...toLonLat(points[i])))
			}
			data = [e.lnglat[0], e.lnglat[2]]
		}
		return {
			target: e,
			type: type,
			data: data
		}
	}
  /**
	 * 判断矢量图形形状
	 * e 等同于 feature.getGeometry()
	 */
	judgeShape(e) {
		let type = e.getType()
		if (type === 'Polygon') {
			let arr = e.getCoordinates().flat()
			if (arr.length === 5) {
				const rect = arr.slice(0, 4)
				if ((rect[0][0] === rect[1][0] && rect[0][1] === rect[3][1]) || (rect[0][1] === rect[1][1] && rect[0][0] === rect[3][0])) {
					type = 'Rectangle'
				}
			}
		} else if (type === 'LineString') {
			type = 'Line'
		}
		return type
	}
  /**
   * 开启编辑
   */
  open () {
    this.initEdit()
  }
  /**
   * 结束编辑
   */
  close () {
    this.modify && this.map.removeGraph(this.modify)
    this.modify = null
  }
  // 事件注册
	on(eventName, callBack = () => {}) {
		if (!eventName || typeof eventName !== 'string') throw new Error('请传入正确的 eventName！')
		if (!this.events.includes(eventName)) return console.warn('无效的事件：' + eventName)
		const eventObject = {
			eventName: 'WGraphEdit(' + eventName + ')',
			callBack,
			handler: e => {
				e.callBack({
					type: e.eventName,
					target: e.target,
					event: e.event
				})
			}
		}
		// 未绑定过事件
		if (!this.WEvents.has(eventObject.eventName)) {
			if (eventObject.eventName === 'WGraphEdit(' + eventName + ')') {
				let eve = document.createEvent('HTMLEvents')
				eve.initEvent(eventName, false, true)
				eve.callBack = callBack
				eventObject.costomEvent = eve
				window.addEventListener(eventName, e => e.callBack && e.callBack(this.drawFeature))
			}
			//储存事件
			this.WEvents.set(eventObject.eventName, eventObject)
		} else {
			const currentEventObject = this.WEvents.get(eventObject.eventName)
			//储存新事件
			this.WEvents.set(currentEventObject.eventName, eventObject)
		}
		this.olTarget && this.olTarget.set('WEvents', this.WEvents)
	}
	//事件移除
	off(eventName, callBack = () => {}) {
		eventName = 'WGraphEdit(' + eventName + ')'
		if (this.WEvents.has(eventName)) {
			// 获取事件对象
			const currentEventObject = this.WEvents.get(eventName)
			// 移除事件
			this.olTarget.un(currentEventObject.eventName, currentEventObject.handler)
			// 删除事件存储
			this.WEvents.delete(eventName)
			this.olTarget && this.olTarget.set('WEvents', this.WEvents)
			callBack()
		}
	}
}

export default WGraphEdit
